/**
 * 【使用方法说明】
 *
 *  1、在 html 文档的 <head> 或 <body> 标签中引入此脚本：<script src="path/FloatBox.js"></script>
 *
 *  2、使用 FloatBox 构造函数，直接实例化一个 FloatBox 类型的对象即可，FloatBox 构造函数可以接收一个对象参数：
 *
 *     new FloatBox({
 *         width:           ,// "漂浮框"的宽度( Number 类型。默认值为 100 )
 *         height:          ,// "漂浮框"的高度( Number 类型。默认值为 60 )
 *         bgColor:         ,// "漂浮框"背景色( String 类型。默认值为 "#ccc"（浅灰色） )
 *         borderRadius:    ,// "漂浮框"边框弧度( Number 类型。默认值为 2 )
 *         closeBtnColor:   ,// "漂浮框"关闭按钮的颜色( String 类型。默认值为 "#000"（黑色） )
 *         speed:           ,// "漂浮框"的移动速度( Number 类型。默认值为 1 )
 *         linkAddr:        ,// 点击"漂浮框"将会跳转到的链接地址( String 类型。默认值为空字符串 "" )
 *         blank:           ,// 上述提到的将会跳转到的链接地址是否在新窗口打开( Boolean 类型。默认值为 false，表示在当前页面打开，而不在新窗口打开 )
 *         imgSrc:          ,// "漂浮框"的背景图片地址( String 类型。默认值为空字符串 "" )
 *     });
 *
 *     对于上述对象参数的属性选项有 2 点需要说明：
 *
 *     (1) 当不给 FloatBox 构造函数传递任何参数时，将全部使用属性选项的默认值。
 *
 *     (2) imgSrc 属性值所代表图片的宽高比应该与 width 除以 height 的值相同，
 *         换句话说就是，最好让图片的宽度值等于 width 的值，高度值等于 height
 *         的值。这样一来就可以保证图片不会变形。
 *
 *  3、最后一点小建议：【不】建议在移动端代码中使用"漂浮窗"效果。
 */

(function ( global ) {
	function standardCompatMode() {
		return document.compatMode === "CSS1Compat" ? true : false;
	}

	function docScrollDistance( direction ) {
		var html = null,
			body = null;
		
		if ( standardCompatMode() )
		{
			html = document.documentElement;
			switch ( direction )
			{
				case "left":
					return html.scrollLeft;
				case "top":
					return html.scrollTop;
			}
		}
		else
		{
			body = document.body;
			switch ( direction )
			{
				case "left":
					return body.scrollLeft;
				case "top":
					return body.scrollTop;
			}
		}
	}

	function viewportSidePosition( side ) {
		var html = null,
			body = null;
		
		if ( standardCompatMode() )
		{
			html = document.documentElement;		
			switch ( side )
			{
				case "top":
					return html.scrollTop;
				case "right":
					return html.scrollLeft + html.clientWidth;
				case "bottom":
					return html.scrollTop + html.clientHeight;
				case "left":
					return html.scrollLeft;
			}
		}
		else
		{
			body = document.body;
			switch( side )
			{
				case "top":
					return body.scrollTop;
				case "right":
					return body.scrollLeft + body.clientWidth;
				case "bottom":
					return body.scrollTop + body.clientHeight;
				case "left":
					return body.scrollLeft;
			}
		}
	}

	/**
	 * [Class] FloatBox
	 */
	function FloatBox( obj ) {		
		var obj = obj === undefined ? {} : obj,
			width = obj.width === undefined ? 100 : obj.width,
			height = obj.height === undefined ? 60 : obj.height,
			bgColor = obj.bgColor === undefined ? "#ccc" : obj.bgColor,
			borderRadius = obj.borderRadius === undefined ? 2 : obj.borderRadius,
			closeBtnColor = obj.closeBtnColor === undefined ? "#fff" : obj.closeBtnColor,
			speed = obj.speed === undefined ? 1 : obj.speed,
			linkAddr = obj.linkAddr === undefined ? "" : obj.linkAddr,
			imgSrc = obj.imgSrc === undefined ? "" : obj.imgSrc;
			
		this.el = document.createElement( "div" );
		this.closeBtn = document.createElement( "span" );
		this.width = width;
		this.height = height;
		this.timer = null;
		this.paused = false;
		this.stop = false;
		this.collidingSide = "top";
		this.moveDirection = "right";
		
		this._init( width, height, bgColor, borderRadius, closeBtnColor, linkAddr, imgSrc );
		this._start( speed );
	}

	FloatBox.prototype._init = function ( width, height, bgColor, borderRadius, closeBtnColor, linkAddr, imgSrc ) {
		this.el.style.position = "absolute";
		this.el.style.left = docScrollDistance( "left" ) + "px";
		this.el.style.top = docScrollDistance( "top" ) + "px";
		this.el.style.width = width + "px";
		this.el.style.height = height + "px";
		this.el.style.backgroundColor = bgColor;
		this.el.style.borderRadius = borderRadius + "px";
		this.el.style.boxShadow = "1px 1px 1px #ccc";
		
		var closeBtnSize = parseInt( this.width * 0.07 );
		this.closeBtn.style.position = "absolute";
		this.closeBtn.style.right = 0;
		this.closeBtn.style.top = -closeBtnSize + "px";
		this.closeBtn.style.width = closeBtnSize + "px";
		this.closeBtn.style.height = closeBtnSize + "px";
		this.closeBtn.style.border = "1px solid " + closeBtnColor;
		this.closeBtn.style.borderRadius = "50%";
		this.closeBtn.style.color = closeBtnColor;
		this.closeBtn.style.textAlign = "center";
		this.closeBtn.style.lineHeight = "1";
		this.closeBtn.style.fontSize = closeBtnSize + "px";
		this.closeBtn.style.cursor = "default";
		this.closeBtn.style.zIndex = "1";
		this.closeBtn.innerHTML = "&times;";
		this.closeBtn.title = "点击关闭飘窗";
		this.el.appendChild( this.closeBtn );
		
		var link = document.createElement( "a" );
		link.href = linkAddr;
		link.style.display = "block";
		link.style.position = "relative";
		link.style.width = "100%";
		link.style.height = "100%";
		this.el.appendChild( link );
		
		var img = null;
		if ( imgSrc !== "" )
		{
			img = document.createElement( "img" );
			img.src = imgSrc;
			img.style.display = "block";
			img.style.position = "relative";
			img.style.width = "100%";
			img.style.height = "100%";
			link.appendChild( img );
		}
		
		document.body.appendChild( this.el );
	};

	FloatBox.prototype._start = function ( speed ) {
		var that = this,
			hasRequestAnimationFrame = typeof requestAnimationFrame === "function" ? true : false;
		
		function move() {
			if ( hasRequestAnimationFrame && that.stop )
			{
				return;
			}
			
			if ( that.paused )
			{
				return;
			}
			
			var boxLeft = parseInt( that.el.style.left ),
				boxTop = parseInt( that.el.style.top ),
				boxRight = boxLeft + that.width,
				boxBottom = boxTop + that.height;
		
			switch ( that.collidingSide )
			{
				case "top":
					if ( that.moveDirection === "right" )
					{
						if ( boxLeft < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
						}
						
						if ( boxTop < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
						}
						
						if ( boxRight + speed > viewportSidePosition( "right" ) &&
							 boxBottom + speed > viewportSidePosition( "bottom" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "left";
						}
						else if ( boxRight + speed > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.collidingSide = "right";
							that.moveDirection = "down";
						}
						else if ( boxBottom + speed > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "right";
						}
						else {
							that.el.style.left = parseInt( that.el.style.left ) + speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) + speed + "px";
						}
					}
					else
					{
						if ( boxRight > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
						}
						
						if ( boxTop < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
						}
						
						if ( boxLeft - speed < viewportSidePosition( "left" ) &&
							 boxBottom + speed > viewportSidePosition( "bottom" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "right";
						}
						else if ( boxLeft - speed < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.collidingSide = "left";
							that.moveDirection = "down";
						}
						else if ( boxBottom + speed > viewportSidePosition( "bottom" ) )
						{
							that.el.style.bottom = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "left";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) - speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) + speed + "px";
						}
					}
					break;
					
				case "right":
					if ( that.moveDirection === "down" )
					{
						if ( boxRight > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
						}
						
						if ( boxTop < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
						}
						
						if ( boxBottom + speed > viewportSidePosition( "bottom" ) &&
							 boxLeft - speed < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "right";
						}
						else if ( boxBottom + speed > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "left";
						}
						else if ( boxLeft - speed < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.collidingSide = "left";
							that.moveDirection = "down";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) - speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) + speed + "px";
						}
					}
					else
					{
						if ( boxRight > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
						}
						
						if ( boxBottom > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
						}
						
						if ( boxTop - speed < viewportSidePosition( "top" ) &&
							 boxLeft - speed < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "right";
						}
						else if ( boxTop - speed < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "left";
						}
						else if ( boxLeft - speed < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.collidingSide = "left";
							that.moveDirection = "up";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) - speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) - speed + "px";
						}
					}
					break;
				
				case "bottom":
					if ( that.moveDirection === "left" )
					{
						if ( boxBottom > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
						}
						
						if ( boxRight > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
						}
						
						if ( boxLeft - speed < viewportSidePosition( "left" ) &&
							 boxTop - speed < viewportSidePosition( "top" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "right";
						}
						else if ( boxLeft - speed < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
							that.collidingSide = "left";
							that.moveDirection = "up";
						}
						else if ( boxTop - speed < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "left";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) - speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) - speed + "px";
						}
					}
					else
					{
						if ( boxBottom > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
						}
						
						if ( boxLeft < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
						}
						
						if ( boxRight + speed > viewportSidePosition( "right" ) &&
							 boxTop - speed < viewportSidePosition( "top" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "left";
						}
						else if ( boxRight + speed > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.collidingSide = "right";
							that.moveDirection = "up";
						}
						else if ( boxTop - speed < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "right";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) + speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) - speed + "px";
						}
					}
					break;
					
				case "left":
					if ( that.moveDirection === "up" )
					{
						if ( boxLeft < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
						}
						
						if ( boxBottom > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
						}
						
						if ( boxTop - speed < viewportSidePosition( "top" ) &&
							 boxRight + speed > viewportSidePosition( "right" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.collidingSide = "top";
							that.moveDirection = "left";
						}
						else if ( boxTop - speed < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
							that.collidingSide = "top";
							that.moveDirection = "right";
						}
						else if ( boxRight + speed > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.collidingSide = "right";
							that.moveDirection = "up";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) + speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) - speed + "px";
						}
					}
					else
					{
						if ( boxLeft < viewportSidePosition( "left" ) )
						{
							that.el.style.left = viewportSidePosition( "left" ) + "px";
						}
						
						if ( boxTop < viewportSidePosition( "top" ) )
						{
							that.el.style.top = viewportSidePosition( "top" ) + "px";
						}
						
						if ( boxBottom + speed > viewportSidePosition( "bottom" ) &&
							 boxRight + speed > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "left";
						}
						else if ( boxBottom + speed > viewportSidePosition( "bottom" ) )
						{
							that.el.style.top = viewportSidePosition( "bottom" ) - that.height + "px";
							that.collidingSide = "bottom";
							that.moveDirection = "right";
						}
						else if ( boxRight + speed > viewportSidePosition( "right" ) )
						{
							that.el.style.left = viewportSidePosition( "right" ) - that.width + "px";
							that.collidingSide = "right";
							that.moveDirection = "down";
						}
						else
						{
							that.el.style.left = parseInt( that.el.style.left ) + speed + "px";
							that.el.style.top = parseInt( that.el.style.top ) + speed + "px";
						}
					}
			}
			
			if ( hasRequestAnimationFrame )
			{
				requestAnimationFrame( move );
			}
		}
			
		if ( hasRequestAnimationFrame )
		{
			requestAnimationFrame( move );
		}
		else
		{
			this.timer = setInterval( move, 30 );
		}
		
		this.el.onmouseover = function () {
			that.paused = true;
		};
		
		this.el.onmouseout = function () {
			that.paused = false;
			if ( hasRequestAnimationFrame )
			{
				requestAnimationFrame( move );
			}
		};
		
		this.closeBtn.onclick = function () {
			that._destroy();
		};
	};

	FloatBox.prototype._destroy = function () {
		clearInterval( this.timer );
		this.stop = true;
		
		this.el.onmouseover = null;
		this.el.onmouseout = null;
		this.closeBtn.onclick = null;
		
		this.el.parentNode.removeChild( this.el );
		this.el = null;
	};
	
	global.FloatBox = FloatBox;
})( this );